﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;
using System.Resources;
using Eudaemon.ProeAssist.Core;
using Eudaemon.ProeAssist.WinGUIControls;
using Eudaemon.ProeAssist.WinGUI.Properties;

namespace Eudaemon.ProeAssist.WinGUI
{
    public partial class MainForm : Form
    {
        #region Private Data Members
        List<ProeFileBundle> proeFileCollection = new List<ProeFileBundle>();
        List<ProeFileBundle> proeFileCollectionSelection = new List<ProeFileBundle>();
        DirectoryWalker walker = new DirectoryWalker();
        bool currentPathChanged;
        FileListView fileList = new FileListView();
        DriveList driveList = new DriveList();
        private ConfigInfo _cfgInfo = new ConfigInfo();
        private ConfigMan _cfgMan = new ConfigMan();
        #endregion

        public MainForm()
        {
            InitializeComponent();
            _cfgInfo = _cfgMan.LoadConfig();
            this.Width = _cfgInfo.MainFormWidth;
            this.Height = _cfgInfo.MainFormHeight;
            this.MainSplitContainer.SplitterDistance = _cfgInfo.LeftPanelWidth;
            walker.CurrentPath = _cfgInfo.LastVisitPath;

            InitControls();
            //for (int i = 0; i < _cfgInfo.ListColunmWidths.Length; ++i )
            //{
            //    fileList.Columns[i].Width = _cfgInfo.ListColunmWidths[i];
            //}

        }

        private void MainForm_Load(object sender, EventArgs e)
        {

        }
        
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            _cfgInfo.MainFormWidth = this.Width;
            _cfgInfo.MainFormHeight = this.Height;
            _cfgInfo.LeftPanelWidth = this.MainSplitContainer.SplitterDistance;
            _cfgInfo.ShowProeFilesOnly = btnShowProeFilesOnly.Checked;
            _cfgInfo.ShowNewestVersionOnly = btnCombineVersion.Checked;
            //_cfgInfo.ListColunmWidths = new int[fileList.Columns.Count];
            //foreach(int i in _cfgInfo.ListColunmWidths)
            //{
            //    int sommmm = fileList.Columns[i].Width;
            //    _cfgInfo.ListColunmWidths[i] = fileList.Columns[i].Width;
            //}
            _cfgInfo.LastVisitPath = walker.CurrentPath;
            _cfgMan.SaveConfig(_cfgInfo);

        }

        #region Initialization
        private void InitControls()
        {
            btnShowProeFilesOnly.CheckState = _cfgInfo.ShowProeFilesOnly ? CheckState.Checked : CheckState.Unchecked;
            btnCombineVersion.CheckState = _cfgInfo.ShowNewestVersionOnly ? CheckState.Checked : CheckState.Unchecked;
            InitDriveList();
            InitFileListView();
            UpdateMainUI();
            fileList.ItemActivate += new EventHandler(fileList_ItemActivate);
            fileList.ItemSelectionChanged += new ListViewItemSelectionChangedEventHandler(fileList_ItemSelectionChanged);
        }

        void fileList_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
        {
            UpdateMainStatusBar();
        }

        private void InitFileListView()
        {
            fileList.Name = "Test files List";
            fileList.Parent = MainSplitContainer.Panel2;
            fileList.Dock = DockStyle.Fill;
            fileList.BeginInit();
            fileList.EndInit();
            ImageList smallImageList = new ImageList();
            AddProeTypeImage(smallImageList, new ProeAssemblyType());
            AddProeTypeImage(smallImageList, new ProeDiagramType());
            AddProeTypeImage(smallImageList, new ProeDrawingType());
            AddProeTypeImage(smallImageList, new ProeFormatType());
            AddProeTypeImage(smallImageList, new ProeLayoutType());
            AddProeTypeImage(smallImageList, new ProeManufacturingType());
            AddProeTypeImage(smallImageList, new ProeMarkupType());
            AddProeTypeImage(smallImageList, new ProePartType());
            AddProeTypeImage(smallImageList, new ProeReportType());
            AddProeTypeImage(smallImageList, new ProeSketchType());
            fileList.SmallImageList = smallImageList;
        }

        private void AddProeTypeImage(ImageList smallImageList, ProeFileType proeType)
        {
            smallImageList.Images.Add(proeType.Name, proeType.IconResource);
        }

        private void InitDriveList()
        {
            driveList.Name = "Test Drive List";
            driveList.Parent = MainSplitContainer.Panel1;
            driveList.Dock = DockStyle.Fill;
            driveList.BeginInit();
            driveList.EndInit();
            ToolStripButton btn;
            foreach (ToolStripItem item in driveList.Items)
            {
                if (item is ToolStripButton)
                {
                    btn = (ToolStripButton)item;
                    btn.Click += new EventHandler(driveListBtn_Click);
                }
            }
        }

        #endregion

        #region Update functions
        private void UpdateMainUI()
        {
            currentPathChanged = (walker.CurrentPath != tbCurrentPath.Text) ? true : false;
            UpdateMainMenu();
            UpdateMainToolBar();
            UpdateDriveList();
            UpdateFileList();
            UpdateMainStatusBar();
        }

        /// <summary>
        ///  Update other controls: driveList, fileList and Main toolbar/menu/statusbar.
        /// </summary>
        private void UpdateMainToolBar()
        {
            tbCurrentPath.Text = walker.CurrentPath;
            BtnUpward.Enabled = walker.UpwardEnabled();
            btnForward.Enabled = walker.ForwardEnabled();
            btnBackward.Enabled = walker.BackwardEnabled();
            btnShowProeFilesOnly.CheckState = _cfgInfo.ShowProeFilesOnly ? CheckState.Checked : CheckState.Unchecked;
            btnCombineVersion.CheckState = _cfgInfo.ShowNewestVersionOnly ? CheckState.Checked : CheckState.Unchecked;
        }

        private void UpdateMainMenu()
        {

        }

        private void UpdateMainStatusBar()
        {
            // Count files and folders in the file list
            int fileCount = fileList.Items.Count;
            labelFileStats.Text = fileList.SelectedItems.Count.ToString() + " selected, " + fileCount.ToString() + " in total.";
        }

        private void UpdateDriveList()
        {
            driveList.SetListChecked(walker.CurrentPath);
        }

        private void UpdateFileList()
        {
            FetchFileList();
        }
        #endregion

        #region Main Menu event handlers

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void contentsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            const string HELP_FILENAME = "Help.txt";
            try
            {
                Process.Start(Path.Combine(Application.StartupPath, HELP_FILENAME));
            }
            catch 
            {
                MessageBox.Show(HELP_FILENAME + " not found in " + Application.StartupPath);
            }
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutForm frm = new AboutForm();
            frm.ShowDialog();
        }

        private void selectAllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (fileList.Items.Count <= 0)
                return;
            fileList.Focus();
            foreach (ListViewItem item in fileList.Items)
                item.Selected = true;
            //SendKeys.Send("+{END}"); 
        }
        #endregion

        #region Main Toolbar event handlers
        private void BtnUpward_Click(object sender, EventArgs e)
        {
            walker.UpLevel();
            UpdateMainUI();
        }

        private void btnBackward_Click(object sender, EventArgs e)
        {
            walker.MovePrevious();
            UpdateMainUI();
        }

        private void btnForward_Click(object sender, EventArgs e)
        {
            walker.MoveNext();
            UpdateMainUI();
        }

        private void btnRefresh_Click(object sender, EventArgs e)
        {
            walker.CurrentPath = tbCurrentPath.Text;
            driveList.RefreshList();
            UpdateMainUI();
        }

        private void tbCurrentPath_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                btnRefresh_Click(sender, e);
            }
        }

        private void btnShowProeFilesOnly_Click(object sender, EventArgs e)
        {
            btnShowProeFilesOnly.CheckState = (btnShowProeFilesOnly.Checked) ? CheckState.Checked : CheckState.Unchecked;
            _cfgInfo.ShowProeFilesOnly = btnShowProeFilesOnly.Checked;
            UpdateMainUI();
        }


        private void btnCombineVersion_Click(object sender, EventArgs e)
        {
            btnCombineVersion.CheckState = (btnCombineVersion.Checked) ? CheckState.Checked : CheckState.Unchecked;
            _cfgInfo.ShowNewestVersionOnly = btnCombineVersion.Checked;
            UpdateMainUI();
        }

        private void btnBackup_Click(object sender, EventArgs e)
        {
            if (fileList.SelectedItems.Count <= 0)
                return;
            GenerateSelectedProeFileList();

            SaveFileDialog dlgSaveFile = new SaveFileDialog();
            dlgSaveFile.InitialDirectory = walker.CurrentPath;
            dlgSaveFile.Filter = "Zip files (*.zip)|*.zip|Tar files (*.tar)|*.tar|Gzip Tar files (*.tgz)|*.tgz|Rar files (*.rar)|*.rar|7zip files (*.7z )|*.7z";

            if (dlgSaveFile.ShowDialog() == DialogResult.OK)
            {
                string archiveFileName = dlgSaveFile.FileName;
                ProcessStartInfo startInfo = new ProcessStartInfo();
                try
                {
                    startInfo.FileName = Path.Combine(Application.StartupPath, "7z.exe");
                    startInfo.ErrorDialog = true;
                    startInfo.Arguments = "a ";
                    startInfo.Arguments += archiveFileName;

                    foreach (ProeFileBundle bundle in proeFileCollectionSelection)
                    {
                        startInfo.Arguments += " " + Path.Combine(walker.CurrentPath,
                            bundle.FileNameWithExtension + "." + bundle.NewestVersion.ToString());
                    }

                    Process archiveProcess = Process.Start(startInfo);
                    // Update after the archive process is finished
                    while (!archiveProcess.HasExited)
                    {
                        System.Threading.Thread.Sleep(5);
                    };
                    UpdateMainUI();
                }
                catch
                {
                }
            }
        }


        private void btnCleanUp_Click(object sender, EventArgs e)
        {
            if (fileList.SelectedItems.Count <= 0)
                return;
            GenerateSelectedProeFileList();
            List<string> proeFileList = new List<string>();
            foreach (ProeFileBundle bundle in proeFileCollectionSelection)
            {
                foreach (int version in bundle.GetAllVersions())
                {
                    if (version == bundle.NewestVersion)
                        continue;
                    proeFileList.Add(bundle.FileNameWithExtension + "." + version.ToString());
                }
            }
            DialogResult result = MessageBox.Show(this, "Really delete old versions of selected ProE files?",
                "Delete Confirmation", MessageBoxButtons.YesNo,
                MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
            if (result == DialogResult.No)
                return;
            FileInfo deleteFileInfo;
            foreach (string fileName in proeFileList)
            {
                deleteFileInfo = new FileInfo(Path.Combine(walker.CurrentPath, fileName));
                try
                {
                    deleteFileInfo.Delete();
                }
                catch
                {
                }
            }
            UpdateMainUI();
        }

        #endregion

        #region DriveList event handlers
        private void driveListBtn_Click(object sender, EventArgs e)
        {
            if (sender is ToolStripButton)
            {
                ToolStripButton btn = (ToolStripButton)sender;
                walker.CurrentPath = btn.ToolTipText;
                UpdateMainUI();
            }
        }
        #endregion

        #region FileList event handlers

        void fileList_ItemActivate(object sender, EventArgs e)
        {
            string sPath = walker.CurrentPath;
            string sFileName = fileList.FocusedItem.Text;
            string sFullPath = Path.Combine(sPath, sFileName);
            bool isFolder, isFile;
            isFolder = Directory.Exists(sFullPath);
            isFile = File.Exists(sFullPath);
            if (!isFolder && !isFile)
                return;
            if (isFolder)
            {
                walker.CurrentPath = sFullPath;
                UpdateMainUI();
            }
            else if (isFile)
            {
                try
                {
                    Process.Start(sFullPath);
                }
                catch
                {
                }
            }
        }

        #endregion

        #region Subroutines
        /// <summary>
        /// The method is similar to part of FetchFileList(),
        /// to which Reconstruction is needed in future.
        /// </summary>
        private void GenerateSelectedProeFileList()
        {
            proeFileCollectionSelection.Clear();

            List<string> selectedProeFileNames = new List<string>();
            foreach (ListViewItem item in fileList.SelectedItems)
            {
                // if the second column has the form
                if (item.SubItems[2].Text.Length > 0)
                {
                    selectedProeFileNames.Add(item.SubItems[0].Text + "." + item.SubItems[2].Text);
                }
            }

            ProeFileBundle currentBundle;
            bool alreadyContained;
            foreach (string fileName in selectedProeFileNames)
            {
                currentBundle = new ProeFileBundle(fileName);
                alreadyContained = false;
                foreach (ProeFileBundle bundle in proeFileCollectionSelection)
                {
                    if (currentBundle.Equals(bundle))
                    {
                        alreadyContained = true;
                        bundle.Add(currentBundle.NewestVersion);
                        break;
                    }
                }
                if (!alreadyContained)
                {
                    proeFileCollectionSelection.Add(currentBundle);
                }
            }
        }


        /// <summary>
        /// Get all files and folders under the current directory.
        /// Add them to the list view.
        /// </summary>
        private void FetchFileList()
        {
            if (!Directory.Exists(walker.CurrentPath))
                return;
            fileList.Items.Clear();
            proeFileCollection.Clear();
            if (currentPathChanged)
                proeFileCollection.Clear();
            DirectoryInfo di = new DirectoryInfo(walker.CurrentPath);

            //delegate void DelegateAddItem();  
            //DelegateAddItem AddListViewItem = delegate()
            //{
            //    ListViewItem dir_item = new ListViewItem(directory.Name);
            //    dir_item.SubItems.Add(@"<Folder>");
            //    dir_item.SubItems.Add("");
            //    dir_item.SubItems.Add("");
            //    dir_item.SubItems.Add(directory.LastAccessTime.ToString());
            //    dir_item.SubItems.Add(directory.CreationTime.ToString());
            //    unsafe
            //    {
            //        hImgSmall = Win32.SHGetFileInfo(directory.FullName, 0, ref shinfo,
            //                                         (uint)System.Runtime.InteropServices.Marshal.SizeOf(shinfo),
            //                                          Win32.SHGFI_ICON |
            //                                          Win32.SHGFI_SMALLICON);
            //        System.Drawing.Icon myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon);
            //        fileList.SmallImageList.Images.Add(myIcon);
            //        dir_item.ImageIndex = fileList.SmallImageList.Images.Count - 1;
            //    }
            //    fileList.Items.Add(dir_item);
            //}
            /* Folder item */
            RebuildIconList();
            IntPtr hImgSmall;    // the handle to the system small image list
            SHFILEINFO shinfo = new SHFILEINFO();
            DirectoryInfo[] dirs = di.GetDirectories();
            foreach (DirectoryInfo directory in dirs)
            {
                ListViewItem dir_item = new ListViewItem(directory.Name);
                dir_item.SubItems.Add(@"<Folder>");
                dir_item.SubItems.Add("");
                dir_item.SubItems.Add("");
                dir_item.SubItems.Add(directory.LastAccessTime.ToString());
                dir_item.SubItems.Add(directory.CreationTime.ToString());
                unsafe
                {
                    hImgSmall = Win32.SHGetFileInfo(directory.FullName, 0, ref shinfo,
                                                     (uint)System.Runtime.InteropServices.Marshal.SizeOf(shinfo),
                                                      Win32.SHGFI_ICON |
                                                      Win32.SHGFI_SMALLICON);
                    System.Drawing.Icon myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon);
                    fileList.SmallImageList.Images.Add(myIcon);
                    dir_item.ImageIndex = fileList.SmallImageList.Images.Count - 1;
                }
                fileList.Items.Add(dir_item);
            }
            
            FileInfo[] files = di.GetFiles();
            List<FileInfo> proeFileList = new List<FileInfo>();
            List<FileInfo> otherFileList = new List<FileInfo>();
            foreach (FileInfo file in files)
            {
                if (ProeFileType.IsProeFileName(file.Name)) 
                    proeFileList.Add(file);
                else
                    otherFileList.Add(file);
            }

            ListViewItem file_item;
            const double BYTE2KB = 1024.0d;
            string strFileSize;
            double fileSize;
            /* Pro/E files item */
            ProeFileBundle currentBundle;
            bool alreadyContained;
            foreach (FileInfo file in proeFileList)
            {
                currentBundle = new ProeFileBundle(file.Name);
                alreadyContained = false;
                foreach (ProeFileBundle bundle in proeFileCollection)
                {
                    if (currentBundle.Equals(bundle))
                    {
                        alreadyContained = true;
                        bundle.Add(currentBundle.NewestVersion);
                        break;
                    }
                }
                if (!alreadyContained)
                {
                    proeFileCollection.Add(currentBundle);
                }
            }
            foreach (ProeFileBundle bundle in proeFileCollection)
            {
                if (_cfgInfo.ShowNewestVersionOnly)
                {
                    file_item = new ListViewItem(bundle.FileNameWithExtension);
                    file_item.SubItems.Add(bundle.FileType.Name);
                    file_item.SubItems.Add(bundle.NewestVersion.ToString());
                    file_item.ImageKey = bundle.FileType.Name;
                    string strFullFileName = bundle.FileNameWithExtension + "." + bundle.NewestVersion.ToString();
                    FileInfo file = new FileInfo(Path.Combine(walker.CurrentPath, strFullFileName));
                    fileSize = file.Length / BYTE2KB;
                    strFileSize = String.Format("{0:F1}", fileSize);
                    file_item.SubItems.Add(strFileSize);
                    file_item.SubItems.Add(file.LastAccessTime.ToString());
                    file_item.SubItems.Add(file.CreationTime.ToString());
                    fileList.Items.Add(file_item);             
                }
                else
                {
                    foreach(int version in bundle.GetAllVersions())
                    {
                        file_item = new ListViewItem(bundle.FileNameWithExtension);
                        file_item.SubItems.Add(bundle.FileType.Name);
                        file_item.SubItems.Add(version.ToString());
                        file_item.ImageKey = bundle.FileType.Name;
                        string strFullFileName = bundle.FileNameWithExtension + "." + version.ToString();
                        FileInfo file = new FileInfo(Path.Combine(walker.CurrentPath, strFullFileName));
                        fileSize = file.Length / BYTE2KB;
                        strFileSize = String.Format("{0:F1}", fileSize);
                        file_item.SubItems.Add(strFileSize);
                        file_item.SubItems.Add(file.LastAccessTime.ToString());
                        file_item.SubItems.Add(file.CreationTime.ToString());
                        fileList.Items.Add(file_item);      
                    }
                }
            }

            /* Other files item */
            if (!_cfgInfo.ShowProeFilesOnly)
            {
                foreach (FileInfo file in otherFileList)
                {
                    file_item = new ListViewItem(file.Name);
                    file_item.SubItems.Add("");
                    file_item.SubItems.Add("");
                    fileSize = file.Length / BYTE2KB;
                    strFileSize = String.Format("{0:F1}", fileSize);
                    file_item.SubItems.Add(strFileSize);
                    file_item.SubItems.Add(file.LastAccessTime.ToString());
                    file_item.SubItems.Add(file.CreationTime.ToString());
                    fileList.Items.Add(file_item);
                    unsafe
                    {
                        hImgSmall = Win32.SHGetFileInfo(file.FullName, 0, ref shinfo,
                                                          (uint)System.Runtime.InteropServices.Marshal.SizeOf(shinfo),
                                                           Win32.SHGFI_ICON |
                                                           Win32.SHGFI_SMALLICON);
                        System.Drawing.Icon myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon);
                        fileList.SmallImageList.Images.Add(myIcon);
                        file_item.ImageIndex = fileList.SmallImageList.Images.Count - 1;
                    }
                }
            }

        }

        /// <summary>
        /// Delete all icons except for proe icons
        /// </summary>
        private void RebuildIconList()
        {
            const int PROE_ICON_COUNT = 10;
            for(int i = PROE_ICON_COUNT; i < fileList.SmallImageList.Images.Count; ++i)
                fileList.SmallImageList.Images.RemoveAt(i);
        }

        #endregion
    }
}